package com.xpec.c4.service.ioc;

import java.util.HashMap;
import java.util.HashSet;
import java.util.Set;

import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;

import com.xpec.c4.service.annotations.Name;
import com.xpec.c4.service.contexts.Contexts;
import com.xpec.c4.service.contexts.ScopeType;
import com.xpec.c4.service.exceptions.IocException;
import com.xpec.c4.service.ioc.cglib.CglibProxy;

/**
 * Ioc的容器
 * 
 * @author lipeilin
 * 
 */
public class IocContainer {

	private static final Log log = LogFactory.getLog(IocContainer.class);

	private static final HashMap<Class<?>, Object> primitiveClass = new HashMap<Class<?>, Object>();

	/**
	 * 代理实现
	 */
	private static IocProxy proxy = new CglibProxy();

	static {

		primitiveClass.put(boolean.class, false);
		primitiveClass.put(byte.class, (byte) 0);
		primitiveClass.put(char.class, (char) 0);
		primitiveClass.put(short.class, (short) 0);
		primitiveClass.put(int.class, (int) 0);
		primitiveClass.put(long.class, (long) 0);
		primitiveClass.put(float.class, (float) 0);
		primitiveClass.put(double.class, (double) 0);

		primitiveClass.put(Boolean.class, false);
		primitiveClass.put(Byte.class, (byte) 0);
		primitiveClass.put(Character.class, (char) 0);
		primitiveClass.put(Short.class, (short) 0);
		primitiveClass.put(Integer.class, (int) 0);
		primitiveClass.put(Long.class, (long) 0);
		primitiveClass.put(Float.class, (float) 0);
		primitiveClass.put(Double.class, (double) 0);
	}

	/**
	 * 创建对象
	 * 
	 * @param <T>
	 * @param clazz
	 * @return
	 */
	@SuppressWarnings("unchecked")
	public static <T> T createObject(Class<T> clazz) {
		if (primitiveClass.containsKey(clazz)) {
			return (T) primitiveClass.get(clazz);
		}
		Object obj = null;

		Name nameSpace = clazz.getAnnotation(Name.class);
		String contextName = null;
		ScopeType scopetype = null;

		// 如果是带有Name，则判断是否需要从Contexts上获得
		if (nameSpace != null) {
			// 取得名称
			contextName = nameSpace.name();
			// 如果没有定义名称，则用类名
			if (contextName == null || contextName.length() == 0) {
				contextName = clazz.getName();
			}

			// 取得context的周期设置
			scopetype = nameSpace.scopeType();
			obj = Contexts.lookupInContext(contextName, scopetype);

			if (obj == null) {
				obj = createNewObject(clazz);
				Contexts.putInContexts(contextName, obj, scopetype);
			}
		}
		// 不需要通过Contexts处理
		else {
			obj = createNewObject(clazz);
		}

		IocAction.inObject(obj);
		return (T) obj;
	}

	private static <T> Object createNewObject(Class<T> clazz) {
		Object obj;
		// 获得代理的类型
		Set<ProxyType> proxyTypes = getProxyTypes(clazz);

		// 如果需要代理
		if (proxyTypes.size() > 0) {
			obj = proxy.createObject(clazz, proxyTypes);
		}
		// 否则只要产生普通对象即可
		else {
			obj = createNormalObject(clazz);
		}
		return obj;
	}
	
	@SuppressWarnings("unchecked")
	public static <T> Class<T> getClass(Class<T> clazz) {
		Class<T> cla;
		// 获得代理的类型
		Set<ProxyType> proxyTypes = getProxyTypes(clazz);
		
		// 如果需要代理
		if (proxyTypes.size() > 0) {
			cla = (Class<T>)proxy.getProxyClass(clazz, proxyTypes);
		}
		// 否则只要产生普通即可
		else {
			cla = clazz;
		}
		return cla;
	}

	/**
	 * 创建一个
	 * 
	 * @param <T>
	 * @param clazz
	 * @return
	 */
	private static <T> Object createNormalObject(Class<T> clazz) {
		Object obj;
		try {
			obj = clazz.newInstance();
		} catch (InstantiationException e) {
			log.error(clazz, e);
			throw new IocException(e);
		} catch (IllegalAccessException e) {
			log.error(clazz, e);
			throw new IocException(e);
		}
		return obj;
	}

	/**
	 * 创建对象，并通过构造函数进行Context注入
	 * 
	 * @param <T>
	 * @param clazz
	 * @return
	 */
	@SuppressWarnings("unchecked")
	public static <T> T createObject(Class<T> clazz, Class[] argumentTypes,
			String[] argumentNames) {
		if (primitiveClass.containsKey(clazz)) {
			return (T) primitiveClass.get(clazz);
		}
		Object obj = null;

		// 获得代理的类型
		Set<ProxyType> proxyTypes = getProxyTypes(clazz);

		// 通过Context得到对应参数名称的参数值
		Object[] arguments = new Object[argumentTypes.length];
		for (int i = 0; i < argumentNames.length; i++) {
			arguments[i] = Contexts.lookupInContexts(argumentNames[i]);
		}

		// 如果需要代理
		if (proxyTypes.size() > 0) {
			obj = proxy.createObject(clazz, proxyTypes, argumentTypes,
					arguments);
		}
		// 否则只要产生普通对象即可
		else {
			obj = createNormalObject(clazz);
		}
		return (T) obj;
	}

	/**
	 * 创建对象
	 * 
	 * @param <T>
	 * @param clazz
	 * @return
	 */
	@SuppressWarnings("unchecked")
	public static <T> T createObject(Class<T> clazz, Class[] argumentTypes,
			Object[] arguments) {
		if (primitiveClass.containsKey(clazz)) {
			return (T) primitiveClass.get(clazz);
		}
		Object obj = null;

		// 获得代理的类型
		Set<ProxyType> proxyTypes = getProxyTypes(clazz);

		// 如果需要代理
		if (proxyTypes.size() > 0) {
			obj = proxy.createObject(clazz, proxyTypes, argumentTypes,
					arguments);
		}
		// 否则只要产生普通对象即可
		else {
			obj = createNormalObject(clazz);
		}
		return (T) obj;
	}

	/**
	 * 创建对象。<br>
	 * 注意，参数对象必须不能为空！
	 * 
	 * @param <T>
	 * @param clazz
	 * @param arguments
	 * @return
	 *
	 * @author lipeilin
	 * @2010-12-13 下午04:55:30
	 */
	@SuppressWarnings("unchecked")
	public static <T> T createObject(Class<T> clazz, Object[] arguments) {
		Class[] argumentTypes = new Class[arguments.length];
		for (int i = 0; i < arguments.length; i++) {
			argumentTypes[i] = arguments[i].getClass();
		}
		return createObject(clazz, argumentTypes, arguments);
	}

	private static <T> Set<ProxyType> getProxyTypes(Class<T> clazz) {
		Set<ProxyType> proxyTypes = new HashSet<ProxyType>();
		// 如果是带有@out，则需要代理
		if (IocManager.isOutClass(clazz)) {
			proxyTypes.add(ProxyType.OUT);
		}

		// 如果是带有@Log，则需要代理
		if (IocManager.isLogClass(clazz)) {
			proxyTypes.add(ProxyType.LOGGER);
		}
		return proxyTypes;
	}

	/**
	 * 创建对象，强制代理
	 * 
	 * @param <T>
	 * @param clazz
	 * @return
	 */
	@SuppressWarnings("unchecked")
	static <T> T createObject(Class<T> clazz, boolean isProxy) {
		Object obj = null;
		// 强制产生对象
		if (isProxy) {
			obj = createObject(clazz);
		}
		// 强制产生非代理对象
		else {
			try {
				obj = clazz.newInstance();
			} catch (InstantiationException e) {
				log.error(clazz, e);
				throw new IocException(e);
			} catch (IllegalAccessException e) {
				log.error(clazz, e);
				throw new IocException(e);
			}
		}
		return (T) obj;
	}

	public static IocProxy getProxy() {
		return proxy;
	}

	/**
	 * 判断是否代理类
	 * 
	 * @param targetClass
	 * @return
	 */
	public static boolean isProxy(Class<?> targetClass) {
		return proxy.isProxy(targetClass);
	}

	/**
	 * 判断是否代理对象
	 * 
	 * @param obj
	 * @return
	 */
	public static boolean isProxy(Object obj) {
		return proxy.isProxy(obj.getClass());
	}

	/**
	 * 取得对象的类。 如果是代理类，则取实际的类；如果不是代理，则返回真正的类
	 * 
	 * @param targetClass
	 * @return
	 */
	public static Class<?> getRealClass(Class<?> targetClass) {
		return proxy.getRealClass(targetClass);
	}

}
